#!/usr/bin/perl

use strict;
use File::Spec;
use File::Basename;
use Getopt::Long;

sub canon($) {
	my $path = shift;
	my $cur = File::Spec->curdir();
	my $up = File::Spec->updir();
	my @parts = File::Spec->splitdir("$path");
	if (($parts[0])&&
	    ($parts[0] ne $cur)&&
	    ($parts[0] ne $up)) {
		$path = $cur.File::Spec->catfile('',$cur, @parts);
	}
	return $path;
}

sub getfiles($) {
	my $opath = shift;
	local *DIR;
	my @files = ();
	my @pathtotreat = ($opath);

	my $cur = File::Spec->curdir();
	my $up = File::Spec->updir();

	while (@pathtotreat) {
		my $thepath = shift @pathtotreat;
		if (-d "$thepath") {
			if (opendir(*DIR,"$thepath")) {
				while (my $f = readdir(*DIR)) {
					if (($f ne $cur)&&($f ne $up)) {
						my $fullpath = File::Spec->catfile("$thepath","$f");
						if (-d "$fullpath") {
							push @pathtotreat, "$fullpath";
						}
						else {
							push @files, canon("$fullpath");
						}
					}
				}
				closedir(*DIR);
			}
			else {
				print STDERR "$thepath: $!\n";
			}
		}
		elsif (-e "$thepath") {
			push @files, canon("$thepath");
		}
	}

	return @files;
}

sub matchMotif($\@) {
	my $filename = shift;
	my $result;
	my $or = 0;
	foreach my $motif (@{$_[0]}) {
		if ($motif eq '&') {
			$or = 0;
		}
		elsif ($motif eq '|') {
			$or = 1;
		}
		else {
			my $localresult = 0;
			if ($motif =~ /^\^(.*)$/) {
				my $m = "$1";
				$localresult = ($filename !~ /^$m$/);
			}		
			else {
				$localresult = ($filename =~ /^$motif$/);
			}
			if (defined($result)) {
				if ($or) {
					$result = $result || $localresult;
				}
				else {
					$result = $result && $localresult;
				}
			}
			else {
				$result = $localresult;
			}
			$or = 0;
		}
	}
	return $result;
}

my @expr = ();
my $negation = 0;

if (!GetOptions('name=s' => sub {
				if ((@expr)&&($expr[$#expr] ne '&')&&($expr[$#expr] ne '|')&&
				    ($expr[$#expr] ne '!')&&($expr[$#expr] ne '^')) {
					push @expr, '&';
				}
				push @expr, $_[1];
			},
		'nname=s' => sub { 
				if ((@expr)&&($expr[$#expr] ne '&')&&($expr[$#expr] ne '|')&&
				    ($expr[$#expr] ne '!')&&($expr[$#expr] ne '^')) {
					push @expr, '&';
				}
				push @expr, '!', $_[1];
			},
		'path=s' => sub{
				if ((@expr)&&($expr[$#expr] ne '&')&&($expr[$#expr] ne '|')&&
				    ($expr[$#expr] ne '!')&&($expr[$#expr] ne '^')) {
					push @expr, '&';
				}
				push @expr, '^', $_[1];
			},
		'npath=s' => sub{
				if ((@expr)&&($expr[$#expr] ne '&')&&($expr[$#expr] ne '|')&&
				    ($expr[$#expr] ne '!')&&($expr[$#expr] ne '^')) {
					push @expr, '&';
				}
				push @expr, '!', '^', $_[1];
			},
		'o' => sub {
				push @expr, '|' if (@expr);
			},
		'a' => sub {
				push @expr, '&' if (@expr);
			},
		'not' => sub {
				if ((@expr)&&($expr[$#expr] ne '&')&&($expr[$#expr] ne '|')&&
				    ($expr[$#expr] ne '!')&&($expr[$#expr] ne '^')) {
					push @expr, '&';
				}
				push @expr, '!';
			},
		)) {
	exit(1);
}

my $directory = shift @ARGV || die("no directory specified\n");
die("no pattern specified\n") unless (@expr);

foreach my $m (@expr) {
	$m =~ s/([.-])/\\$1/g;
	$m =~ s/\*/.*/g;
	$m =~ s/\?/\\./g;
}

my @files = getfiles("$directory");

foreach my $file (@files) {
	if (matchMotif($file,@expr)) {
		print "$file\n";
	}
}

exit(0);


